#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <sys/types.h>
//#include <strings.h>

#include "static_component_loader.h"
#include "omx_base_component.h"

struct BOSA_COMPONENTLOADER OmxWin_static_loader;

extern int Omx_LibrarySetup_AudioEncoderAMR(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_AudioDecoderAMR(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_VideoEncoderMpeg4(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_VideoDecoderMpeg4(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_VideoEncoderMpeg4VP(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_VideoDecoderMpeg4VP(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_AudioDecoderMP3(OmxWinLoaderComponentType **OmxWinComponents);
//lin extern int Omx_LibrarySetup_AudioReaderBinary(OmxWinLoaderComponentType **OmxWinComponents);
//lin extern int Omx_LibrarySetup_AudioWriterBinary(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_AudioDecoderAACHE(OmxWinLoaderComponentType **OmxWinComponents);
//extern int  Omx_LibrarySetup_AudioRendererPcm(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_VideoDecoderH264(OmxWinLoaderComponentType **OmxWinComponents);
extern int Omx_LibrarySetup_ImageDecoderJpeg(OmxWinLoaderComponentType **OmxWinComponents);


typedef int(*plibrary_Setup_omxwin)(OmxWinLoaderComponentType **omxwinComponents);
typedef struct Library_Entry
{
    plibrary_Setup_omxwin component_library_Setup_omxwin;
} Library_Entry;

static Library_Entry OpenMaxComLibEntries[] =
{
//    {Omx_LibrarySetup_AudioDecoderMP3},

	/*{Omx_LibrarySetup_AudioEncoderAMR},
    {Omx_LibrarySetup_AudioDecoderAMR},
    {Omx_LibrarySetup_VideoEncoderMpeg4},
    {Omx_LibrarySetup_VideoDecoderMpeg4},
    {Omx_LibrarySetup_VideoEncoderMpeg4VP},
    {Omx_LibrarySetup_VideoDecoderMpeg4VP},
    {Omx_LibrarySetup_VideoDecoderH264},
    {Omx_LibrarySetup_AudioDecoderAACHE},*/
    {Omx_LibrarySetup_ImageDecoderJpeg}

//    {
//lin        Omx_LibrarySetup_AudioReaderBinary
//    }
//    ,
//    {
//lin        Omx_LibrarySetup_AudioWriterBinary
//    }
 //   ,
#ifndef WIN32
   
    //  {Omx_LibrarySetup_AudioRendererPcm}
#endif
};
#define OPENMAX_LIB_ENTRIES_NUM  (sizeof(OpenMaxComLibEntries)/sizeof(Library_Entry))


/** This pointer holds and handle allocate by this loader and requested by
 * some application. If the IL client does not de-allocate it calling
 * explicitely the FreeHandle function, any pending handle is release at the
 * end, when the global function OMX_Deinit is called. This list takes track of
 * any handle
 */

/** Current number of handles already allocated by this loader
 */

/** @brief The initialization of the ST specific component loader.
 *
 * This function allocates memory for the component loader and initialize other function pointer
 */
void OmxWin_static_InitComponentLoader()
{
    OmxWin_static_loader.BOSA_InitComponentLoader = &BOSA_OmxWin_InitComponentLoader;
    OmxWin_static_loader.BOSA_DeInitComponentLoader = &BOSA_OmxWin_DeInitComponentLoader;
    OmxWin_static_loader.BOSA_CreateComponent = &BOSA_OmxWin_CreateComponent;
    OmxWin_static_loader.BOSA_DestroyComponent = &BOSA_OmxWin_DestroyComponent;
    OmxWin_static_loader.BOSA_ComponentNameEnum = &BOSA_OmxWin_ComponentNameEnum;
    OmxWin_static_loader.BOSA_GetRolesOfComponent = &BOSA_OmxWin_GetRolesOfComponent;
    OmxWin_static_loader.BOSA_GetComponentsOfRole = &BOSA_OmxWin_GetComponentsOfRole;
}

/** @brief the ST static loader contructor
 *
 * This function creates the ST static component loader, and creates
 * the list of available components, based on a registry file
 * created by a separate appication. It is called omxregister,
 * and must be called before the use of this loader
 */
OMX_ERRORTYPE BOSA_OmxWin_InitComponentLoader(BOSA_COMPONENTLOADER *loader)
{
    OmxWinLoaderComponentType **templateList;
    int i;

    DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__);

    templateList = omx_malloc((OPENMAX_LIB_ENTRIES_NUM + 1) *sizeof(OmxWinLoaderComponentType*));
    for (i = 0; i < (OPENMAX_LIB_ENTRIES_NUM + 1); i++)
        templateList[i] = NULL;

    for (i = 0; i < OPENMAX_LIB_ENTRIES_NUM; i++)
    {
        OpenMaxComLibEntries[i].component_library_Setup_omxwin((&templateList[i]));
    }

    loader->loaderPrivate = (void*)templateList;
    DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__);

    return OMX_ErrorNone;
}

/** @brief The destructor of the ST specific component loader.
 *
 * This function deallocates the list of available components.
 */
OMX_ERRORTYPE BOSA_OmxWin_DeInitComponentLoader(BOSA_COMPONENTLOADER *loader)
{
    int i, j, err;
    OmxWinLoaderComponentType **templateList;
    DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__);

    templateList = (OmxWinLoaderComponentType **)loader->loaderPrivate;

    i = 0;
    while (templateList[i])
    {
        if (templateList[i]->name_requested)
        {
            omx_free(templateList[i]->name_requested);
            templateList[i]->name_requested = NULL;
        }

        for (j = 0; j < templateList[i]->name_specific_length; j++)
        {
            if (templateList[i]->name_specific[j])
            {
                omx_free(templateList[i]->name_specific[j]);
                templateList[i]->name_specific[j] = NULL;
            }
            if (templateList[i]->role_specific[j])
            {
                omx_free(templateList[i]->role_specific[j]);
                templateList[i]->role_specific[j] = NULL;
            }
        }

        if (templateList[i]->name_specific)
        {
            omx_free(templateList[i]->name_specific);
            templateList[i]->name_specific = NULL;
        }
        if (templateList[i]->role_specific)
        {
            omx_free(templateList[i]->role_specific);
            templateList[i]->role_specific = NULL;
        }

        if (templateList[i]->name)
        {
            omx_free(templateList[i]->name);
            templateList[i]->name = NULL;
        }
#ifdef USE_RESOURCE_MANAGEMENT
        {
            NodeComponentEntity *tmp,  *node;
            node = templateList[i]->sComEntitiesQueue.pHeader;
            while (node)
            {
                tmp = node->pNext;
                if (node->pComponentEntity)
                    omx_free(node->pComponentEntity);
                node = tmp;
            }
        }

#endif
        omx_free(templateList[i]);
        templateList[i] = NULL;
        i++;

    }
    if (templateList)
    {
        omx_free(templateList);
        templateList = NULL;
    }

    DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__);
    return OMX_ErrorNone;
}

/** @brief creator of the requested openmax component
 *
 * This function searches for the requested component in the internal list.
 * If the copmponent is found, its constructor is called,
 * and the standard callback are assigned.
 * A pointer to a standard openmax component is returned.
 */
OMX_ERRORTYPE BOSA_OmxWin_CreateComponent(BOSA_COMPONENTLOADER *loader, OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks)
{

    int i, j;
    int componentPosition =  - 1;
    OMX_ERRORTYPE eError = OMX_ErrorNone;
    OmxWinLoaderComponentType **templateList;
    OMX_COMPONENTTYPE *openmaxStandComp;
    omx_base_component_PrivateType *priv;

    DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__);
    templateList = (OmxWinLoaderComponentType **)loader->loaderPrivate;
    i = 0;
    while (templateList[i])
    {
        if (!strcmp(templateList[i]->name, cComponentName))
        {
            //given component name matches with the general component names
            componentPosition = i;
            break;
        }
        else
        {
            for (j = 0; j < templateList[i]->name_specific_length; j++)
            {
                if (!strcmp(templateList[i]->name_specific[j], cComponentName))
                {
                    //given component name matches with specific component names
                    componentPosition = i;
                    break;
                }
            }
            if (componentPosition !=  - 1)
            {
                break;
            }
        }
        i++;
    }
    if (componentPosition ==  - 1)
    {
        DEBUG(DEB_LEV_ERR, "Component not found with current ST static component loader.\n");
        return OMX_ErrorComponentNotFound;
    }

    //component name matches with general component name field
    DEBUG(DEB_LEV_PARAMS, "Found base requested template %s\n", cComponentName);
    /* Build ST component from template and fill fields */
#if 0
    templateList[componentPosition]->name_requested = strndup(cComponentName, OMX_MAX_STRINGNAME_SIZE);
#endif

    openmaxStandComp = (OMX_COMPONENTTYPE*)omx_calloc(1, sizeof(OMX_COMPONENTTYPE));
    if (!openmaxStandComp)
    {
        return OMX_ErrorInsufficientResources;
    }
    eError = templateList[componentPosition]->constructor(openmaxStandComp, cComponentName);
    if (eError != OMX_ErrorNone)
    {
        if (eError == OMX_ErrorInsufficientResources)
        {
            *pHandle = openmaxStandComp;
            return OMX_ErrorInsufficientResources;
        }
        DEBUG(DEB_LEV_ERR, "Error during component construction\n");
        openmaxStandComp->ComponentDeInit(openmaxStandComp);
        omx_free(openmaxStandComp);
        openmaxStandComp = NULL;
        return OMX_ErrorComponentNotFound;
    }
    priv = (omx_base_component_PrivateType*)openmaxStandComp->pComponentPrivate;
    priv->loader = (void*)loader;

    *pHandle = openmaxStandComp;
    ((OMX_COMPONENTTYPE*) * pHandle)->SetCallbacks(*pHandle, pCallBacks, pAppData);

#ifdef USE_RESOURCE_MANAGEMENT
    openmaxStandComp->SendCommand = omx_ResourceMgt_SendCommand;
    priv->pCompAbstract = (void*)templateList[componentPosition];
    templateList[componentPosition]->bActive = OMX_FALSE;
#endif

    DEBUG(DEB_LEV_FULL_SEQ, "Template %s found returning from OMX_GetHandle\n", cComponentName);
    DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__);
    return eError;
}

/**************************************************************************/
/*                                                                        */
/**************************************************************************/

OMX_ERRORTYPE BOSA_OmxWin_DestroyComponent(BOSA_COMPONENTLOADER *loader, OMX_HANDLETYPE hComponent)
{
    OMX_ERRORTYPE err = OMX_ErrorNone;
    omx_base_component_PrivateType *priv = (omx_base_component_PrivateType*)((OMX_COMPONENTTYPE*)hComponent)->pComponentPrivate;

    /* check if this component was actually loaded from this loader */
    if (priv->loader != loader)
    {
        return OMX_ErrorComponentNotFound;
    }

#ifdef USE_RESOURCE_MANAGEMENT
    err = FreeResourceRequest((OmxWinLoaderComponentType*)priv->pCompAbstract, (OMX_COMPONENTTYPE*)hComponent);
    if (err != OMX_ErrorNone)
    {
        return err;
    }
#endif
    err = ((OMX_COMPONENTTYPE*)hComponent)->ComponentDeInit(hComponent);

    omx_free((OMX_COMPONENTTYPE*)hComponent);
    hComponent = NULL;

    return err;
}

/** @brief This function search for the index from 0 to end of the list
 *
 * This function searches in the list of ST static components and enumerates
 * both the class names and the role specific components.
 */
OMX_ERRORTYPE BOSA_OmxWin_ComponentNameEnum(BOSA_COMPONENTLOADER *loader, OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex)
{

    OmxWinLoaderComponentType **templateList;
    int i, j, index = 0;
    int found = 0;
    DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__);

    templateList = (OmxWinLoaderComponentType **)loader->loaderPrivate;
    i = 0;
    while (templateList[i])
    {
        if (index == nIndex)
        {
            strncpy(cComponentName, templateList[i]->name, nNameLength);
            found = 1;
            break;
        }
        index++;
        if (templateList[i]->name_specific_length > 1)
        {
            for (j = 0; j < templateList[i]->name_specific_length; j++)
            {
                if (index == nIndex)
                {
                    strncpy(cComponentName, templateList[i]->name_specific[j], nNameLength);
                    found = 1;
                    break;
                }
                index++;
            }
        }
        if (found)
        {
            break;
        }
        i++;
    }
    if (!found)
    {
        DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s with OMX_ErrorNoMore\n", __func__);
        return OMX_ErrorNoMore;
    }
    DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__);
    return OMX_ErrorNone;
}

/** @brief The specific version of OMX_GetRolesOfComponent
 *
 * This function replicates exactly the behavior of the
 * standard OMX_GetRolesOfComponent function for the ST static
 * component loader
 */
OMX_ERRORTYPE BOSA_OmxWin_GetRolesOfComponent(BOSA_COMPONENTLOADER *loader, OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles)
{

    OmxWinLoaderComponentType **templateList;
    int i, j, index;
    int max_roles =  *pNumRoles;
    int found = 0;
    DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__);
    templateList = (OmxWinLoaderComponentType **)loader->loaderPrivate;
    *pNumRoles = 0;
    i = 0;
    while (templateList[i])
    {
        if (!strcmp(templateList[i]->name, compName))
        {
            DEBUG(DEB_LEV_SIMPLE_SEQ, "Found requested template %s IN GENERAL COMPONENT\n", compName);
            // set the no of roles field
            *pNumRoles = templateList[i]->name_specific_length;
            if (roles == NULL)
            {
                return OMX_ErrorNone;
            }
            //append the roles
            for (index = 0; index < templateList[i]->name_specific_length; index++)
            {
                if (index < max_roles)
                {
                    strcpy((char*)*(roles + index), templateList[i]->role_specific[index]);
                }
            }
            found = 1;
        }
        else
        {
            for (j = 0; j < templateList[i]->name_specific_length; j++)
            {
                if (!strcmp(templateList[i]->name_specific[j], compName))
                {
                    DEBUG(DEB_LEV_SIMPLE_SEQ, "Found requested component %s IN SPECIFIC COMPONENT \n", compName);
                    *pNumRoles = 1;
                    found = 1;
                    if (roles == NULL)
                    {
                        return OMX_ErrorNone;
                    }
                    if (max_roles > 0)
                    {
                        strcpy((char*) * roles, templateList[i]->role_specific[j]);
                    }
                }
            }
        }
        i++;
        if (found)
        {
            break;
        }
    }
    if (!found)
    {
        DEBUG(DEB_LEV_ERR, "no component match in whole template list has been found\n");
        *pNumRoles = 0;
        return OMX_ErrorComponentNotFound;
    }
    DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__);
    return OMX_ErrorNone;
}

/** @brief The specific version of OMX_GetComponentsOfRole
 *
 * This function replicates exactly the behavior of the
 * standard OMX_GetComponentsOfRole function for the ST static
 * component loader
 */
OMX_ERRORTYPE BOSA_OmxWin_GetComponentsOfRole(BOSA_COMPONENTLOADER *loader, OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames)
{

    OmxWinLoaderComponentType **templateList;
    int i = 0, j = 0;
    int num_comp = 0;
    int max_entries =  *pNumComps;

    DEBUG(DEB_LEV_FUNCTION_NAME, "In %s\n", __func__);
    templateList = (OmxWinLoaderComponentType **)loader->loaderPrivate;
    i = 0;
    while (templateList[i])
    {
        for (j = 0; j < templateList[i]->name_specific_length; j++)
        {
            if (!strcmp(templateList[i]->role_specific[j], role))
            {
                if (compNames != NULL)
                {
                    if (num_comp < max_entries)
                    {
                        strcpy((char*)(compNames[num_comp]), templateList[i]->name);
                    }
                }
                num_comp++;
            }
        }
        i++;
    }

    *pNumComps = num_comp;
    DEBUG(DEB_LEV_FUNCTION_NAME, "Out of %s\n", __func__);
    return OMX_ErrorNone;
}
